﻿using GDGeek;
using MrPP.Myth;
using MrPP.UX;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

namespace MrPP.SerriedCabinet
{

    public interface IShelveViewModel {

        int getPage();
        string[] getScanList();
        BoxLocation getLocation();
        bool getRunning(); 
        Dictionary<string, BoxLocation> getBinding();


    }
    public abstract  class ShelveAbstract :MonoBehaviour{

        public IShelveViewModel model { set; get; }
        public abstract void onPage(int value);
        public abstract void onScanList(string[] list);
        public abstract void onLocation(BoxLocation location);
        public abstract void onRunning(bool value);
        public abstract void onBinding(Dictionary<string, BoxLocation> data);

    }
    public class ShelveViewModel : NetworkBehaviour, IShelveModel, IBridgeReceiver, IShelveViewModel
    {
        [SerializeField]
        private List<ShelveAbstract> _callback = new List<ShelveAbstract>();
        [SerializeField]
        //private ShelveBinding _binding;

        //服务器广播running_
        [SyncVar(hook = "onRunning")]
        private bool running_ = false;

        private void onRunning(bool value)
        {
            running_ = value;
          //  _binding.onRunning?.Invoke(running_);
            _callback.ForEach(item => item.onRunning(running_));
        }


        //服务器广播
        [SyncVar(hook = "onPage")]
        private int page_ = 0;

        private void onPage(int value)
        {

            page_ = value;
           // _binding.onPage?.Invoke(page_);
            _callback.ForEach(item => item.onPage(page_));
        }

        [SyncVar(hook = "onLocation")]
        private BoxLocation location_;

        private void onLocation(BoxLocation value)
        {

            location_ = value;
           // _binding.onLocation?.Invoke(location_);
            _callback.ForEach(item => item.onLocation(location_));
        }
        public struct Data {
            public string sn;
            public BoxLocation location;

            public static bool operator !=(Data lhs,
                                           Data rhs)
            {
                return lhs.Equals(rhs);
            }
            public static bool operator ==(Data lhs,
                                           Data rhs)
            {
                return !lhs.Equals(rhs);
            }

            public override bool Equals(object obj)
            {
                return obj is Data data &&
                       sn == data.sn;
            }

            public override int GetHashCode()
            {
                return -266417372 + EqualityComparer<string>.Default.GetHashCode(sn);
            }
        }
        public class DataSyncList : SyncListStruct<Data>
        {
        
        }

        // [SyncVar(hook = "dataChanged")]
        public DataSyncList datas_ = new DataSyncList();


        private Dictionary<string, BoxLocation> map_ = new Dictionary<string, BoxLocation>();

        public SyncListString scanList_ = new SyncListString();
        public void Awake()
        {
            _callback.ForEach(item => item.model = this);


          //  _binding.getPage = delegate { return page_; };
           // _binding.getRunning = delegate {
          //      return running_; 
          //  };


          //  _binding.getScanList = delegate {

           //     string[] ret = new string[scanList_.Count];
           //     scanList_.CopyTo(ret, 0);
           //     return ret;
          //  };

           // _binding.getBinding = delegate { return map_; };

          //  _binding.getLocation = delegate { return this.location_; };
            datas_.Callback += dataCallback;
            scanList_.Callback += scanCallback;
            location_.box = -1;
        }

        private void scanCallback(SyncList<string>.Operation op, int itemIndex)
        {
            string[] ret = new string[scanList_.Count];
            scanList_.CopyTo(ret, 0);
           // _binding.onScanList.Invoke(ret);
            _callback.ForEach(item => item.onScanList(ret));
        }

        private void dataCallback(SyncList<Data>.Operation op, int itemIndex)
        {
            map_.Clear();
            foreach (var data in datas_) {
                map_[data.sn] = data.location;
            }
          //  _binding.onBinding?.Invoke(map_);
            _callback.ForEach(item => item.onBinding(map_));
        }

        public string handle => this.longName();


        public void broadcast(string evt, object data)
        {
            switch (evt) {
                case "page_":
                    page_ = (int)(data);
                    break;
                case "running_":
                    running_ = (bool)(data);
                    break;

                case "location_":
                    BoxLocation bl = JsonUtility.FromJson<BoxLocation>((string)(data));
                    Debug.LogError((string)(data));
                    if (location_.box == -1)
                    {
                        location_ = bl;
                    }
                    else if(location_.box == bl.box && location_.layer == bl.layer && location_.sile == bl.sile && location_.type == bl.type)
                    {
                        BoxLocation empty = new BoxLocation();
                        empty.box = -1;
                        location_ = empty;

                    }
                    break;
                case "@binding":
                    @binding((int)(data));
                    break;
                case "@scanning":
                    @scanning((string)(data));
                    break;
            }
        }
        private void @scanning(string data)
        {
            for (int i = 0; i < scanList_.Count; ++i) {
                if (scanList_[i] == data) {
                    return;
                }
            }
            scanList_.Add(data);
        }
        private void @binding(int index)
        {
            if (index >= 0 && index < scanList_.Count) {
                string sn = scanList_[index];
                if (this.location_.box != -1)
                {
                    Data data;
                    data.sn = sn;
                    data.location = this.location_;
                    if (datas_.Contains(data))
                    {
                        datas_.Remove(data);

                    }
                    else {
                        datas_.Add(data);
                    }
                }
            }
        }

        public void Start() {
            BridgeBroadcast.Instance.addReceiver(this);
        }
        public void OnDestroy() {
            if (BridgeBroadcast.IsInitialized) { 
                BridgeBroadcast.Instance.removeReceiver(this);
            }
        }
        //本地发送
        public void doLast()
        {

            Bridge.Instance.post(this.longName(), "page_", page_ - 1);
        }

        public void doNext()
        {
            Bridge.Instance.post(this.longName(), "page_", page_ + 1);
        }

        public void doBinding(int id)
        {
            Bridge.Instance.post(this.longName(), "@binding", id);
        }

       

        public void doPlay()
        {

            Bridge.Instance.post(this.longName(), "running_", true);
        }

        public void doStop()
        {
            Bridge.Instance.post(this.longName(), "running_", false);
        }

        public void doScanning(string sn)
        {


            Bridge.Instance.post(this.longName(), "@scanning", sn);
        }

        public void doSelected(BoxLocation location)
        {
            Bridge.Instance.post(this.longName(), "location_", JsonUtility.ToJson(location));
        }
      
        public int getPage()
        {
            return page_;
        }

        public string[] getScanList()
        {
            string[] ret = new string[scanList_.Count];
            scanList_.CopyTo(ret, 0);
            return ret;
        }

        public BoxLocation getLocation()
        {
            return this.location_;
        }

        public bool getRunning()
        {
            return running_;
        }

        public Dictionary<string, BoxLocation> getBinding()
        {
            return map_;
        }
    }
}
